//-----------------------------------------------------------------
//
// Copyright (c) 2022-2024 Zhengde
// All rights reserved.
//
//-----------------------------------------------------------------
//                         biRISC-V CPU
//                            V0.8.1
//                     Ultra-Embedded.com
//                     Copyright 2019-2020
//
//                   admin@ultra-embedded.com
//
//                     License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//-----------------------------------------------------------------

module biriscv_frontend
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
    parameter SUPPORT_BRANCH_PREDICTION = 1 ,
    parameter SUPPORT_MULDIV   = 1          ,
    parameter SUPPORT_MMU      = 1          ,
    parameter EXTRA_DECODE_STAGE = 0        ,
    parameter NUM_BTB_ENTRIES  = 32         ,
    parameter NUM_BTB_ENTRIES_W = 5         ,
    parameter NUM_BHT_ENTRIES  = 512        ,
    parameter NUM_BHT_ENTRIES_W = 9         ,
    parameter RAS_ENABLE       = 1          ,
    parameter GSHARE_ENABLE    = 0          ,
    parameter BHT_ENABLE       = 1          ,
    parameter NUM_RAS_ENTRIES  = 8          ,
    parameter NUM_RAS_ENTRIES_W = 3         
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
    // Inputs
    input           clk                        ,
    input           rst_n                      ,
    input           icache_accept_i            ,
    input           icache_valid_i             ,
    input           icache_error_i             ,
    input  [ 63:0]  icache_inst_i              ,
    input           icache_page_fault_i        ,
    input           fetch0_accept_i            ,
    input           fetch1_accept_i            ,
    input           fetch_invalidate_i         ,
    input           branch_request_i           ,
    input  [ 31:0]  branch_pc_i                ,
    input  [  1:0]  branch_priv_i              ,
    input           branch_info_request_i      ,
    input           branch_info_is_taken_i     ,
    input           branch_info_is_not_taken_i ,
    input  [ 31:0]  branch_info_source_i       ,
    input           branch_info_is_call_i      ,
    input           branch_info_is_ret_i       ,
    input           branch_info_is_jmp_i       ,
    input  [ 31:0]  branch_info_pc_i           ,

    // Outputs
    output          icache_rd_o                ,
    output          icache_flush_o             ,
    output          icache_invalidate_o        ,
    output [ 31:0]  icache_pc_o                ,
    output [  1:0]  icache_priv_o              ,
    output          fetch0_valid_o             ,
    output [ 31:0]  fetch0_instr_o             ,
    output [ 31:0]  fetch0_pc_o                ,
    output          fetch0_fault_fetch_o       ,
    output          fetch0_fault_page_o        ,
    output          fetch0_instr_exec_o        ,
    output          fetch0_instr_lsu_o         ,
    output          fetch0_instr_branch_o      ,
    output          fetch0_instr_mul_o         ,
    output          fetch0_instr_div_o         ,
    output          fetch0_instr_csr_o         ,
    output          fetch0_instr_rd_valid_o    ,
    output          fetch0_instr_invalid_o     ,
    output          fetch1_valid_o             ,
    output [ 31:0]  fetch1_instr_o             ,
    output [ 31:0]  fetch1_pc_o                ,
    output          fetch1_fault_fetch_o       ,
    output          fetch1_fault_page_o        ,
    output          fetch1_instr_exec_o        ,
    output          fetch1_instr_lsu_o         ,
    output          fetch1_instr_branch_o      ,
    output          fetch1_instr_mul_o         ,
    output          fetch1_instr_div_o         ,
    output          fetch1_instr_csr_o         ,
    output          fetch1_instr_rd_valid_o    ,
    output          fetch1_instr_invalid_o     
);

    wire           fetch_valid_w;
    wire  [ 63:0]  fetch_instr_w;
    wire           fetch_fault_page_w;
    wire  [ 31:0]  next_pc_f_w;
    wire  [  1:0]  next_taken_f_w;
    wire  [ 31:0]  fetch_pc_f_w;
    wire           fetch_accept_w;
    wire  [  1:0]  fetch_pred_branch_w;
    wire  [ 31:0]  fetch_pc_w;
    wire           fetch_fault_fetch_w;
    wire           fetch_pc_accept_w;


    biriscv_npc
    #(
        .NUM_BTB_ENTRIES              (NUM_BTB_ENTRIES)           ,
        .SUPPORT_BRANCH_PREDICTION    (SUPPORT_BRANCH_PREDICTION) ,
        .GSHARE_ENABLE                (GSHARE_ENABLE)             ,
        .NUM_RAS_ENTRIES_W            (NUM_RAS_ENTRIES_W)         ,
        .NUM_BHT_ENTRIES_W            (NUM_BHT_ENTRIES_W)         ,
        .BHT_ENABLE                   (BHT_ENABLE)                ,
        .NUM_BTB_ENTRIES_W            (NUM_BTB_ENTRIES_W)         ,
        .NUM_BHT_ENTRIES              (NUM_BHT_ENTRIES)           ,
        .RAS_ENABLE                   (RAS_ENABLE)                ,
        .NUM_RAS_ENTRIES              (NUM_RAS_ENTRIES)           
    )
    u_npc
    (
        // Inputs
        .clk                      (clk)                        ,
        .rst_n                    (rst_n)                      ,
        .invalidate_i             (1'b0)                       ,
        .branch_request_i         (branch_info_request_i)      ,
        .branch_is_taken_i        (branch_info_is_taken_i)     ,
        .branch_is_not_taken_i    (branch_info_is_not_taken_i) ,
        .branch_source_i          (branch_info_source_i)       ,
        .branch_is_call_i         (branch_info_is_call_i)      ,
        .branch_is_ret_i          (branch_info_is_ret_i)       ,
        .branch_is_jmp_i          (branch_info_is_jmp_i)       ,
        .branch_pc_i              (branch_info_pc_i)           ,
        .pc_f_i                   (fetch_pc_f_w)               ,
        .pc_accept_i              (fetch_pc_accept_w)          ,
    
        // Outputs
        .next_pc_f_o              (next_pc_f_w)    ,
        .next_taken_f_o           (next_taken_f_w) 
    );
    

    biriscv_decode
    #(
        .EXTRA_DECODE_STAGE    (EXTRA_DECODE_STAGE) ,
        .SUPPORT_MULDIV        (SUPPORT_MULDIV)     
    )
    u_decode
    (
        // Inputs
        .clk                            (clk)                 ,
        .rst_n                          (rst_n)               ,
        .fetch_in_valid_i               (fetch_valid_w)       ,
        .fetch_in_instr_i               (fetch_instr_w)       ,
        .fetch_in_pred_branch_i         (fetch_pred_branch_w) ,
        .fetch_in_fault_fetch_i         (fetch_fault_fetch_w) ,
        .fetch_in_fault_page_i          (fetch_fault_page_w)  ,
        .fetch_in_pc_i                  (fetch_pc_w)          ,
        .fetch_out0_accept_i            (fetch0_accept_i)     ,
        .fetch_out1_accept_i            (fetch1_accept_i)     ,
        .branch_request_i               (branch_request_i)    ,
        .branch_pc_i                    (branch_pc_i)         ,
        .branch_priv_i                  (branch_priv_i)       ,
    
        // Outputs
        .fetch_in_accept_o              (fetch_accept_w)           ,
        .fetch_out0_valid_o             (fetch0_valid_o)           ,
        .fetch_out0_instr_o             (fetch0_instr_o)           ,
        .fetch_out0_pc_o                (fetch0_pc_o)              ,
        .fetch_out0_fault_fetch_o       (fetch0_fault_fetch_o)     ,
        .fetch_out0_fault_page_o        (fetch0_fault_page_o)      ,
        .fetch_out0_instr_exec_o        (fetch0_instr_exec_o)      ,
        .fetch_out0_instr_lsu_o         (fetch0_instr_lsu_o)       ,
        .fetch_out0_instr_branch_o      (fetch0_instr_branch_o)    ,
        .fetch_out0_instr_mul_o         (fetch0_instr_mul_o)       ,
        .fetch_out0_instr_div_o         (fetch0_instr_div_o)       ,
        .fetch_out0_instr_csr_o         (fetch0_instr_csr_o)       ,
        .fetch_out0_instr_rd_valid_o    (fetch0_instr_rd_valid_o)  ,
        .fetch_out0_instr_invalid_o     (fetch0_instr_invalid_o)   ,
        .fetch_out1_valid_o             (fetch1_valid_o)           ,
        .fetch_out1_instr_o             (fetch1_instr_o)           ,
        .fetch_out1_pc_o                (fetch1_pc_o)              ,
        .fetch_out1_fault_fetch_o       (fetch1_fault_fetch_o)     ,
        .fetch_out1_fault_page_o        (fetch1_fault_page_o)      ,
        .fetch_out1_instr_exec_o        (fetch1_instr_exec_o)      ,
        .fetch_out1_instr_lsu_o         (fetch1_instr_lsu_o)       ,
        .fetch_out1_instr_branch_o      (fetch1_instr_branch_o)    ,
        .fetch_out1_instr_mul_o         (fetch1_instr_mul_o)       ,
        .fetch_out1_instr_div_o         (fetch1_instr_div_o)       ,
        .fetch_out1_instr_csr_o         (fetch1_instr_csr_o)       ,
        .fetch_out1_instr_rd_valid_o    (fetch1_instr_rd_valid_o)  ,
        .fetch_out1_instr_invalid_o     (fetch1_instr_invalid_o)   
    );


    biriscv_fetch
    #(
         .SUPPORT_MMU    (SUPPORT_MMU)
    )
    u_fetch
    (
        // Inputs
        .clk                    (clk)                 ,
        .rst_n                  (rst_n)               ,
        .fetch_accept_i         (fetch_accept_w)      ,
        .icache_accept_i        (icache_accept_i)     ,
        .icache_valid_i         (icache_valid_i)      ,
        .icache_error_i         (icache_error_i)      ,
        .icache_inst_i          (icache_inst_i)       ,
        .icache_page_fault_i    (icache_page_fault_i) ,
        .fetch_invalidate_i     (fetch_invalidate_i)  ,
        .branch_request_i       (branch_request_i)    ,
        .branch_pc_i            (branch_pc_i)         ,
        .branch_priv_i          (branch_priv_i)       ,
        .next_pc_f_i            (next_pc_f_w)         ,
        .next_taken_f_i         (next_taken_f_w)      ,
    
        // Outputs
        .fetch_valid_o          (fetch_valid_w)       ,
        .fetch_instr_o          (fetch_instr_w)       ,
        .fetch_pred_branch_o    (fetch_pred_branch_w) ,
        .fetch_fault_fetch_o    (fetch_fault_fetch_w) ,
        .fetch_fault_page_o     (fetch_fault_page_w)  ,
        .fetch_pc_o             (fetch_pc_w)          ,
        .icache_rd_o            (icache_rd_o)         ,
        .icache_flush_o         (icache_flush_o)      ,
        .icache_invalidate_o    (icache_invalidate_o) ,
        .icache_pc_o            (icache_pc_o)         ,
        .icache_priv_o          (icache_priv_o)       ,
        .pc_f_o                 (fetch_pc_f_w)        ,
        .pc_accept_o            (fetch_pc_accept_w)   
    );

endmodule
